package com.blood.config.aop;

import cn.hutool.json.JSONUtil;
import com.blood.core.resp.BusinessException;
import com.blood.core.resp.GlobalResultStatus;
import com.blood.core.resp.ResponseResult;
import com.blood.core.util.http.HttpRequestUtils;
import com.blood.core.util.http.RequestTheadUtils;
import com.blood.modules.system.dto.req.SysLogSaveReq;
import com.blood.modules.system.service.ISysLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;

/**
 * @author yelong
 * @date 2020/12/3 17:16
 * @description 所有controller aop
 * @Copyright
 */
@Aspect
@Component
@Slf4j
public class ControllerAop {

    @Autowired
    private HttpServletRequest request;
    @Autowired
    private ISysLogService sysLogService;

    @Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
    public void allMethodOfController() {
    }

    @Around("allMethodOfController()")
    public Object around(ProceedingJoinPoint joinPoint) {
        String requestURI = HttpRequestUtils.getFullRequestURI(request);

        Object[] argsBefore = joinPoint.getArgs();
        Object[] args = new Object[argsBefore.length];
        // 移除无法被序列化的参数
        for (int i = 0; i < argsBefore.length; i++) {
            Object argBefore = argsBefore[i];
            if (argBefore instanceof ServletRequest || argBefore instanceof ServletResponse
                    || argBefore instanceof MultipartFile || argBefore instanceof List) {
                continue;
            }

            args[i] = argBefore;
        }

        String parameter;
        try {
            parameter = JSONUtil.toJsonStr(args);
        } catch (Exception e) {
            parameter = Arrays.toString(args);
        }
        log.info("{} 请求参数 {}", requestURI, parameter);
        long startTime = System.currentTimeMillis();
        try {
            Object proceed = joinPoint.proceed();
            long endTime = System.currentTimeMillis();
            if (proceed == null) {
                log.info("{} 响应结果 {}", requestURI, "null");
            } else {
                if (proceed.getClass() != Void.class) {
                    String jsonString = JSONUtil.toJsonStr(proceed);
                    log.debug("{} 响应结果 {}", requestURI, jsonString);
                }
                log.debug("{} 请求处理时间 {} ms", requestURI, endTime - startTime);
            }

            return proceed;
        } catch (BusinessException e) {
            log.error(requestURI + " 异常信息：", e);
            return new ResponseResult<Void>(false, e.getErrorCode(), e.getErrorMsg(), null);

        } catch (Throwable throwable) {
            log.error(requestURI + " 异常信息：", throwable);
            //保存错误日志
            SysLogSaveReq req = new SysLogSaveReq();

            StringBuffer errorInfo = new StringBuffer();
            errorInfo.append("请求参数 ")
                    .append(parameter)
                    .append(" 错误日志")
                    .append(throwable)
                    .append(": ");
            try {
                errorInfo.append(throwable.getStackTrace()[0].toString());
            } catch (Exception e) {

            }
            req.setInfo(errorInfo.toString());
            sysLogService.saveInfo(req);
            return GlobalResultStatus.SYS_ERROR.toResult().responseEmptyBody();
        } finally {
            RequestTheadUtils.remove();
        }
    }
}
